package com.tsfyun.scm.service.impl.finance;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tsfyun.common.base.dto.Result;
import com.tsfyun.common.base.enums.DistributedLockEnum;
import com.tsfyun.common.base.enums.NumberConditionEnum;
import com.tsfyun.common.base.enums.finance.TransactionCategoryEnum;
import com.tsfyun.common.base.enums.finance.TransactionTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.scm.dto.finance.TransactionFlowQTO;
import com.tsfyun.scm.dto.finance.client.ClientTransactionFlowQTO;
import com.tsfyun.scm.entity.finance.TransactionFlow;
import com.tsfyun.scm.mapper.finance.TransactionFlowMapper;
import com.tsfyun.scm.service.finance.ITransactionFlowService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.vo.finance.CustomerBalanceVO;
import com.tsfyun.scm.vo.finance.TransactionFlowVO;
import com.tsfyun.scm.vo.finance.client.ClientTransactionListVO;
import com.tsfyun.common.base.dto.TransactionFlowDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * <p>
 * 交易流水 服务实现类
 * </p>
 *

 * @since 2020-04-16
 */
@RefreshScope
@Slf4j
@Service
public class TransactionFlowServiceImpl extends ServiceImpl<TransactionFlow> implements ITransactionFlowService {

    @Autowired
    private TransactionFlowMapper transactionFlowMapper;

    @Autowired
    private RedisLockRegistry redisLockRegistry;

    @Value("${redis.lock.time:5}")
    private Integer lockTime;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recordTransactionFlow(TransactionFlowDTO param) {
        String lockKey = DistributedLockEnum.RECORD_TRANSACTION.getCode() + ":"  + param.getCustomerId();
        Lock lock = redisLockRegistry.obtain(lockKey);
        boolean isLock;
        try {
            isLock = lock.tryLock(lockTime, TimeUnit.SECONDS);
            if(!isLock) {
                log.error(String.format("未获取到锁，客户：【%s】",param.getCustomerId()));
                throw new ServiceException("服务拥挤，请稍后再试");
            }
            BigDecimal currentBalance = getCustomerBalance(param.getCustomerId());
            currentBalance = Objects.isNull(currentBalance) ? BigDecimal.ZERO : currentBalance;
            log.info("客户：【{}】，当前余额：【{}】，交易额：【{}】，交易类别：【{}】，交易类型：【{}】",param.getCustomerId(),currentBalance,param.getAmount(),
                    TransactionCategoryEnum.of(param.getTransactionCategory()).getName(), TransactionTypeEnum.of(param.getTransactionType()).getName());

            TransactionFlow transactionFlow = new TransactionFlow();
            transactionFlow.setCustomerId(param.getCustomerId());
            transactionFlow.setAmount(param.getAmount());
            transactionFlow.setTransactionCategory(param.getTransactionCategory());
            transactionFlow.setTransactionType(param.getTransactionType());
            transactionFlow.setTransactionNo(param.getTransactionNo());
            BigDecimal afterTransactionBalance = BigDecimal.ZERO;
            if(Objects.equals(TransactionCategoryEnum.OUTCOME.getCode(),param.getTransactionCategory())) {//支出
                afterTransactionBalance = currentBalance.subtract(param.getAmount()).setScale(2, BigDecimal.ROUND_HALF_UP);
            } else if(Objects.equals(TransactionCategoryEnum.INCOME.getCode(),param.getTransactionCategory())) {//收入
                afterTransactionBalance = currentBalance.add(param.getAmount()).setScale(2, BigDecimal.ROUND_HALF_UP);
            }
            transactionFlow.setBalance(afterTransactionBalance);
            transactionFlow.setMemo(StringUtils.null2EmptyWithTrim(param.getMemo()));
            if(transactionFlow.getMemo().length()>500){
                transactionFlow.setMemo(transactionFlow.getMemo().substring(0,499));
            }
            super.saveNonNull(transactionFlow);
        } catch (InterruptedException e) {
            log.error("记录交易流水获取锁异常",e);
            throw new ServiceException("服务拥挤，请稍后再试");
        } finally {
            //释放锁
            lock.unlock();
        }
    }

    @Override
    public BigDecimal getCustomerBalance(Long customerId) {
        return transactionFlowMapper.getBalance(customerId);
    }

    @Override
    public PageInfo<TransactionFlowVO> pageList(TransactionFlowQTO qto) {
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        Map param = beanMapper.map(qto, Map.class);
        if(StringUtils.isNotEmpty(qto.getAmountCondition())) {
            param.put("amountCondition", NumberConditionEnum.of(qto.getAmountCondition()).getSymbol());
        }
        List<TransactionFlowVO> list = transactionFlowMapper.list(param);
        return new PageInfo<>(list);
    }

    @Override
    public Result<ClientTransactionListVO> clientPageList(ClientTransactionFlowQTO qto) {
        PageHelper.startPage(qto.getPage(),qto.getLimit());
        qto.setCustomerId(SecurityUtil.getCurrentCustomerId());
        List<TransactionFlowVO> list = transactionFlowMapper.clientList(qto);
        PageInfo<TransactionFlowVO> page = new PageInfo<>(list);
        //合计本次查询范围内的收入与支出
        Map<String,BigDecimal> transactionSum = transactionFlowMapper.sumInOutcome(qto);
        ClientTransactionListVO clientTransactionListVO = new ClientTransactionListVO();
        clientTransactionListVO.setTransactions(list);
        if(Objects.nonNull(transactionSum)) {
            clientTransactionListVO.setIncomeAmount(transactionSum.getOrDefault("income", BigDecimal.ZERO));
            clientTransactionListVO.setOutcomeAmount(transactionSum.getOrDefault("outcome", BigDecimal.ZERO));
        }
        return Result.success((int)page.getTotal(),clientTransactionListVO);
    }

    @Override
    public CustomerBalanceVO getCustomerInoutBalance(Long customerId) {
        CustomerBalanceVO customerBalanceVO = new CustomerBalanceVO();
        BigDecimal balance = getCustomerBalance(customerId);
        //合计本次查询范围内的收入与支出
        ClientTransactionFlowQTO qto = new ClientTransactionFlowQTO();
        qto.setCustomerId(customerId);
        Map<String,BigDecimal> transactionSum = transactionFlowMapper.sumInOutcome(qto);
        customerBalanceVO.setBalance(balance);
        if(Objects.nonNull(transactionSum)) {
            customerBalanceVO.setIncomeAmount(transactionSum.getOrDefault("income", BigDecimal.ZERO));
            customerBalanceVO.setOutcomeAmount(transactionSum.getOrDefault("outcome", BigDecimal.ZERO));
        }
        return customerBalanceVO;
    }


}
